package crypto

import (
	"io"
	"crypto/rand"
	"crypto/aes"
	"crypto/cipher"
	"errors"

	"golang.org/x/crypto/argon2"
)

func MakeSalt() []byte {
	key := [32]byte{}
	_, err := io.ReadFull(rand.Reader, key[:])
	if err != nil {
		panic(err)
	}
	return key[:]
}

// todo memguard password
func DeriveKey(password string, salt []byte) [32]byte {
	// todo memguard
	key := argon2.IDKey([]byte(password), salt, 1, 64*1024, 4, 32)
	// todo memguard
	var keyArr [32]byte
	copy(keyArr[:], key)
	return keyArr
}

// todo memguard plaintext, key
func Encrypt(plaintext []byte, key [32]byte) (ciphertext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	_, err = io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return nil, err
	}

	return gcm.Seal(nonce, nonce, plaintext, nil), nil
}

// todo memguard key
func Decrypt(ciphertext []byte, key [32]byte) (plaintext []byte, err error) {
	block, err := aes.NewCipher(key[:])
	if err != nil {
		return nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, err
	}

	if len(ciphertext) < gcm.NonceSize() {
		return nil, errors.New("malformed ciphertext")
	}

	return gcm.Open(nil,
		ciphertext[:gcm.NonceSize()],
		ciphertext[gcm.NonceSize():],
		nil,
	)
}
